package cn.sh.library.mgts.service.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.io.ResolverUtil.Test;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.missing.Missing;
import org.elasticsearch.search.aggregations.bucket.missing.MissingAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.missing.MissingAggregator;
import org.elasticsearch.search.aggregations.bucket.missing.MissingAggregatorFactory;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.terms.Terms.Bucket;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

import cn.sh.library.mgts.base.InstanceAggField;
import cn.sh.library.mgts.bean.CommonSearchBean;
import cn.sh.library.mgts.bean.InstanceSearchBean;
import cn.sh.library.mgts.bean.PlaceMapBean;
import cn.sh.library.mgts.common.Constant;
import cn.sh.library.mgts.dto.Constructor;
import cn.sh.library.mgts.dto.Pager;
import cn.sh.library.mgts.framework.commonparser.ParseException;
import cn.sh.library.mgts.service.InstanceService;
import cn.sh.library.mgts.service.MergeParts;
import cn.sh.library.mgts.utils.StringUtilC;

@Service
public class InstanceServiceImpl implements InstanceService {
	@Autowired
	RestHighLevelClient highLevelClient;

	@Autowired()
	@Qualifier("placeMap")
	List<Map<String, Object>> placeMap;

	// instance
	@Override
	public Map<String, Object> getInstances(InstanceSearchBean mgtsInstanceSearchBean) {
		Map<String, Object> result = new HashMap<>();

		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		searchSourceBuilder = MergeParts.instanceSearch(mgtsInstanceSearchBean);
		// 分页
		searchSourceBuilder.from(mgtsInstanceSearchBean.getPager().getStartIndex());
		searchSourceBuilder.size(mgtsInstanceSearchBean.getPager().getPageSize());
		// 分面
		searchSourceBuilder = termfacet(searchSourceBuilder);
		searchSourceBuilder.trackTotalHits(true);

		// 高亮
		HighlightBuilder highlightBuilder = new HighlightBuilder();
		highlightBuilder.field("title.label.@value")
				.field("contribution.personName.@value")
				.field("provisionActivity.proOrganization.@value").field("provisionActivity.proPlace.@value");
		highlightBuilder.preTags("<b style='color:red'>");
		highlightBuilder.postTags("</b>");
		searchSourceBuilder.highlighter(highlightBuilder);

		SearchRequest searchRequest = new SearchRequest(Constant.MGTS_INSTANCE_INDEX);
		searchRequest.source(searchSourceBuilder);

		List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
		List<Map<String, Object>> facetList = new ArrayList<Map<String, Object>>();

		try {
//				// 执行search
			SearchResponse searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
			mgtsInstanceSearchBean.getPager().setTook(searchResponse.getTook().getMillis());
			mgtsInstanceSearchBean.getPager().calcPageCount(searchResponse.getHits().getTotalHits().value);// 总数

			// 重新构造结构
			resultList = Constructor.constructorInstance(searchResponse);

			// 分面解析
			facetList = facet(searchResponse);

		} catch (IOException e) {
			e.printStackTrace();
		}
		result.put("resultList", resultList);
		result.put("facetList", facetList);

		return result;
	}
	

	
	@Override
	public List<Map<String, Object>> getPlacesInAreaCount(String freetext, String points, String startYear, String endYear) {
		InstanceSearchBean mgtsInstanceSearchBean = new InstanceSearchBean();
		List<Map<String, String>> cdtns = new ArrayList<>();
		if(StringUtils.isNotBlank(startYear)) {
			Map<String, String> cdtnStart = new HashMap<>();
			cdtnStart.put("field", "YEAR");
			cdtnStart.put("value", startYear);
			cdtnStart.put("logic", "and");
			cdtnStart.put("type", "2");
			cdtns.add(cdtnStart);
		}
		if(StringUtils.isNotBlank(endYear)) {
			Map<String, String> cdtnEnd = new HashMap<>();
			cdtnEnd.put("field", "YEAR");
			cdtnEnd.put("value", endYear);
			cdtnEnd.put("logic", "and");
			cdtnEnd.put("type", "3");
			cdtns.add(cdtnEnd);
		}
		
		mgtsInstanceSearchBean.setFreetext(freetext);
		mgtsInstanceSearchBean.setCdtn(cdtns);
		List<Map<String, Object>> result = new ArrayList<>();
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		searchSourceBuilder = MergeParts.mapSearch(mgtsInstanceSearchBean, points);

		SearchRequest searchRequest = new SearchRequest(Constant.MGTS_INSTANCE_INDEX);
		searchRequest.source(searchSourceBuilder);
		try {
//			// 执行search
			SearchResponse searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
			Map<String, Object> cnt = new HashMap<>();
			cnt.put("cnt", searchResponse.getHits().getTotalHits().value);
			result.add(cnt);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	
	}
	
	@Override
	public List<Map<String, Object>> getPlacesInArea(String freetext, String points, String startYear, String endYear, CommonSearchBean bean) throws ParseException {
		InstanceSearchBean mgtsInstanceSearchBean = new InstanceSearchBean();
		List<Map<String, String>> cdtns = new ArrayList<>();
		if(StringUtils.isNotBlank(startYear)) {
			Map<String, String> cdtnStart = new HashMap<>();
			cdtnStart.put("field", "YEAR");
			cdtnStart.put("value", startYear);
			cdtnStart.put("logic", "and");
			cdtnStart.put("type", "2");
			cdtns.add(cdtnStart);
		}
		if(StringUtils.isNotBlank(endYear)) {
			Map<String, String> cdtnEnd = new HashMap<>();
			cdtnEnd.put("field", "YEAR");
			cdtnEnd.put("value", endYear);
			cdtnEnd.put("logic", "and");
			cdtnEnd.put("type", "3");
			cdtns.add(cdtnEnd);
		}
		
		mgtsInstanceSearchBean.setFreetext(freetext);
		mgtsInstanceSearchBean.setCdtn(cdtns);
		return getPlacesInArea(mgtsInstanceSearchBean, points, bean);
	}

	// 根据坐标获得地名索引
	@Override
	public List<Map<String, Object>> getPlacesInArea(InstanceSearchBean mgtsInstanceSearchBean, String points, CommonSearchBean bean) throws ParseException {
		List<Map<String, Object>> result = new ArrayList<>();
		List<Map<String, Object>> resultPlace = new ArrayList<>();

		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		searchSourceBuilder = MergeParts.mapSearch(mgtsInstanceSearchBean, points);
		
		if(bean != null) {
			BoolQueryBuilder boolQueryBuilder = (BoolQueryBuilder) searchSourceBuilder.query();
			boolQueryBuilder.must(bean.query(Constant.EXPR_FIELD_MAP));
		}

		// 分面
		AggregationBuilder aggPlace = AggregationBuilders.terms("mapPlace").field("provisionActivity.place.uri.keyword")
				.size(Integer.MAX_VALUE);
		searchSourceBuilder.aggregation(aggPlace);
		searchSourceBuilder.trackTotalHits(true);

		SearchRequest searchRequest = new SearchRequest(Constant.MGTS_INSTANCE_INDEX);
		searchRequest.source(searchSourceBuilder);

		try {
//			// 执行search
			SearchResponse searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//			mgtsInstanceSearchBean.getPager().setTook(searchResponse.getTook().getMillis());
//			mgtsInstanceSearchBean.getPager().calcPageCount(searchResponse.getHits().getTotalHits().value);// 总数

			// 分面解析
			Terms terms = searchResponse.getAggregations().get("mapPlace");
			// 初步构造结果集
			for (Bucket bucket : terms.getBuckets()) {
				for (Map<String, Object> place : placeMap) {
//					System.out.println(bucket.getKey());
					Map<String, Object> returnPlace = (Map<String, Object>) place.get(bucket.getKey());
					Map<String, Object> constructPlace = new HashMap<>();
					constructPlace.put("uri", returnPlace.get("uri"));
					constructPlace.put("label", returnPlace.get("chsPlc"));
					constructPlace.put("long", returnPlace.get("long"));
					constructPlace.put("lat", returnPlace.get("lat"));
					constructPlace.put("location", returnPlace.get("location"));
					constructPlace.put("cnt", bucket.getDocCount());
					if(StringUtils.isEmpty(points)) {
						resultPlace.add(constructPlace);
					}else if(MergeParts.mapSearchFilter(returnPlace.get("long").toString(), returnPlace.get("lat").toString(),points)) {
						resultPlace.add(constructPlace);
					}	
				}
			}

			result.addAll(resultPlace);
			// 数据聚合 根据location值
//			Map<Object, List<Map<String, Object>>> indexAndTypeMap = resultPlace.stream()
//					.collect(Collectors.groupingBy(e -> e.get("location")));
//			// 重新构造结果集 如果存在returnPlace的long和lat已有且值一致（如
//			// 浙江与杭州的location是一致的），则将二者的label与uri以逗号拼合
//			for (Entry<Object, List<Map<String, Object>>> m : indexAndTypeMap.entrySet()) {
//				Map<String, Object> constructPlace = new HashMap<>();
//				if (m.getValue().size() > 1) {
//					String uri = "", label = "", longNum = "", latNum = "";
//					for (int i = 0; i < m.getValue().size(); i++) {
//						uri += m.getValue().get(i).get("uri") + ",";
//						label += m.getValue().get(i).get("label") + ",";
//						longNum = m.getValue().get(i).get("long").toString();
//						latNum = m.getValue().get(i).get("lat").toString();
//					}
//					constructPlace.put("uri", uri.substring(0, uri.length() - 1));
//					constructPlace.put("label", label.substring(0, label.length() - 1));
//					constructPlace.put("long", longNum);
//					constructPlace.put("lat", latNum);
//					constructPlace.put("cnt", m.getValue().get(0).get("cnt"));
//					result.add(constructPlace);
//				} else {
//					constructPlace.put("uri", m.getValue().get(0).get("uri"));
//					constructPlace.put("label", m.getValue().get(0).get("label"));
//					constructPlace.put("long", m.getValue().get(0).get("long"));
//					constructPlace.put("lat", m.getValue().get(0).get("lat"));
//					constructPlace.put("cnt", m.getValue().get(0).get("cnt"));
//					result.add(constructPlace);
//				}
//			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}

	// 根据placeUri和freetext获取instance
	@Override
	public Map<String, Object> getInstancesWithPlace(String placeUri, String freetext, String startYear, String endYeaer, Pager pager, CommonSearchBean bean) throws ParseException {
		// placeUri 可能存在多值 以“，”分隔
		Map<String, Object> result = new HashMap<>();

		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		searchSourceBuilder = MergeParts.instanceSearchWithPlace(placeUri, freetext, startYear, endYeaer);

		if(bean != null) {
			BoolQueryBuilder boolQueryBuilder = (BoolQueryBuilder) searchSourceBuilder.query();
			boolQueryBuilder.must(bean.query(Constant.EXPR_FIELD_MAP));
		}

		// 分页
		searchSourceBuilder.from(pager.getStartIndex());
		searchSourceBuilder.size(pager.getPageSize());
		searchSourceBuilder.trackTotalHits(true);

		SearchRequest searchRequest = new SearchRequest(Constant.MGTS_INSTANCE_INDEX);
		searchRequest.source(searchSourceBuilder);
		List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
		try {
			SearchResponse searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
			pager.setTook(searchResponse.getTook().getMillis());
			pager.calcPageCount(searchResponse.getHits().getTotalHits().value);// 总数
			// 重新构造结构
			resultList = Constructor.constructorInstance(searchResponse);
		} catch (IOException e) {
			e.printStackTrace();
		}
		result.put("resultList", resultList);
		return result;
	}

	public Map<String, Object> getClassification() {
		Map<String, Object> result = new HashMap<String, Object>();
		// 分类构造
		QueryBuilder queryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.termQuery("hasInstance", true))
				.must(QueryBuilders.rangeQuery("level.len").lte(2));

		SearchSourceBuilder searchSourceBuilderClass = new SearchSourceBuilder();
		searchSourceBuilderClass.query(queryBuilder);
		searchSourceBuilderClass.size(5000);
		searchSourceBuilderClass.sort("_score").sort(new FieldSortBuilder("level.@value.keyword").order(SortOrder.ASC));
		SearchRequest searchRequestClass = new SearchRequest(Constant.MGTS_CLASS_INDEX);
		searchRequestClass.source(searchSourceBuilderClass);

		List<Map<String, Object>> classList = new ArrayList<Map<String, Object>>();// 所有分类
		try {
			SearchResponse searchResponseClass = highLevelClient.search(searchRequestClass, RequestOptions.DEFAULT);
			classList = Constructor.constructClass(searchResponseClass);

			result.put("classes", classList);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}
	
	@Override
	public Map<String, Object> multsearch(CommonSearchBean bean) throws ParseException {
		Map<String, Object> result = new HashMap<>();

		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//		searchSourceBuilder = MergeParts.instanceSearch(mgtsInstanceSearchBean);
//		// 分页
//		searchSourceBuilder.from(mgtsInstanceSearchBean.getPager().getStartIndex());
//		searchSourceBuilder.size(mgtsInstanceSearchBean.getPager().getPageSize());
//		// 分面
//		searchSourceBuilder = termfacet(searchSourceBuilder);
		boolQueryBuilder.must(bean.query(Constant.EXPR_FIELD_MAP));
		
		searchSourceBuilder = termfacet(searchSourceBuilder);
		searchSourceBuilder.trackTotalHits(true);
		searchSourceBuilder.query(boolQueryBuilder);

		// 高亮
		HighlightBuilder highlightBuilder = new HighlightBuilder();
		highlightBuilder.field("title.label.@value")
				.field("contribution.personName.@value")
				.field("provisionActivity.proOrganization.@value").field("provisionActivity.proPlace.@value");
		highlightBuilder.preTags("<b style='color:red'>");
		highlightBuilder.postTags("</b>");
		searchSourceBuilder.highlighter(highlightBuilder);

		SearchRequest searchRequest = new SearchRequest(Constant.MGTS_INSTANCE_INDEX);
		searchRequest.source(searchSourceBuilder);

		List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
		List<Map<String, Object>> facetList = new ArrayList<Map<String, Object>>();

		try {
//				// 执行search
			SearchResponse searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//			mgtsInstanceSearchBean.getPager().setTook(searchResponse.getTook().getMillis());
			bean.getPager().calcPageCount(searchResponse.getHits().getTotalHits().value);// 总数

			// 重新构造结构
			resultList = Constructor.constructorInstance(searchResponse);

			// 分面解析
			facetList = facet(searchResponse);

		} catch (IOException e) {
			e.printStackTrace();
		}
		result.put("resultList", resultList);
		result.put("facetList", facetList);

		return result;
	}

	@Override
	public Map<String, Object> getWorkDetail(InstanceSearchBean mgtsInstanceSearchBean) {
		Map<String, Object> result = new HashMap<>();
		// 构造检索条件
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		searchSourceBuilder = MergeParts.workDetailSearch(mgtsInstanceSearchBean);

		// 分页
		searchSourceBuilder.from(mgtsInstanceSearchBean.getPager().getStartIndex());
		searchSourceBuilder.size(mgtsInstanceSearchBean.getPager().getPageSize());

		// 解析分面
		searchSourceBuilder = termfacet(searchSourceBuilder);
		searchSourceBuilder.trackTotalHits(true);

		SearchRequest searchRequest = new SearchRequest(Constant.MGTS_INSTANCE_INDEX);
		searchRequest.source(searchSourceBuilder);

		List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
		List<Map<String, Object>> facetList = new ArrayList<Map<String, Object>>();

		try {
//			// 执行search
			SearchResponse searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
			mgtsInstanceSearchBean.getPager().setTook(searchResponse.getTook().getMillis());
			mgtsInstanceSearchBean.getPager().calcPageCount(searchResponse.getHits().getTotalHits().value);// 总数
			// 重新构造结构
			resultList = Constructor.constructorInstance(searchResponse);

			// 分面解析
			facetList = facet(searchResponse);
		} catch (IOException e) {
			e.printStackTrace();
		}
		result.put("resultList", resultList);
		result.put("facetList", facetList);

		return result;
	}

	@Override
	public Map<String, Object> getInstancesDetail(HashMap<String, String> map) {
		Map<String, Object> result = new HashMap<>();
		if (StringUtils.isNotEmpty(map.get("data"))) {
			// 构造检索条件
			SearchSourceBuilder searchSourceBuilder = MergeParts.instanceDetailSearch(map.get("data"));
			List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
			SearchRequest searchRequest = new SearchRequest(Constant.MGTS_INSTANCE_INDEX);
			searchRequest.source(searchSourceBuilder);
			try {
//				// 执行search
				SearchResponse searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
				// 重新构造结构
				resultList = Constructor.constructorInstance(searchResponse);
			} catch (IOException e) {
				e.printStackTrace();
			}
			result = resultList.get(0);
//			result.put("resultList", resultList);
		}
		return result;
	}

	private SearchSourceBuilder termfacetMap(SearchSourceBuilder searchSourceBuilder) {
		// place("place", "provisionActivity.proPlace.@value.keyword"), //出版地分面
		AggregationBuilder aggPlace = AggregationBuilders.terms("provAgg").field("provisionActivity.place.province.keyword")
				.size(Integer.MAX_VALUE)
				.subAggregation(AggregationBuilders.terms("cityAgg").field("provisionActivity.place.chtCty.keyword")
						.size(Integer.MAX_VALUE).subAggregation(AggregationBuilders.terms("countyAgg")
								.field("provisionActivity.place.chsPlc.keyword").size(Integer.MAX_VALUE)));
		searchSourceBuilder.aggregation(aggPlace);
		return searchSourceBuilder;

	}

	// 解析分面
	private SearchSourceBuilder termfacet(SearchSourceBuilder searchSourceBuilder) {
		for (InstanceAggField aggField : InstanceAggField.values()) {
			// 根据 分面类型、分面字段、分面显示条数 构造分面查询
			AggregationBuilder aggregation = AggregationBuilders.terms(aggField.getType()).field(aggField.getField())
					.size(200);
			searchSourceBuilder.aggregation(aggregation);
			// 根据 其他分面类型、分面字段 构造其他分面查询
			AggregationBuilder aggregationOther = AggregationBuilders.missing(aggField.getType() + "Other")
					.field(aggField.getField());
			searchSourceBuilder.aggregation(aggregationOther);
		}
		//增加分面 

//		AggregationBuilder aggregation = AggregationBuilders.terms("accessLevel").field("item.accessLevel.keyword")
//				.size(200);
//		searchSourceBuilder.aggregation(aggregation);
//		// 根据 其他分面类型、分面字段 构造其他分面查询
//		AggregationBuilder aggregationOther = AggregationBuilders.missing("accessLevelOther")
//				.field("item.accessLevel");
//		searchSourceBuilder.aggregation(aggregationOther);
		
		return searchSourceBuilder;
	}

	// 高亮
	List<Map<String, Object>> highlight(SearchResponse searchResponse) {
		// 高亮解析
		for (SearchHit hit : searchResponse.getHits().getHits()) {
			Map<String, HighlightField> highlightField = hit.getHighlightFields();
			System.out.println("==" + highlightField);
			HighlightField content = highlightField.get("name");
			System.out.println("--" + content);
			if (content != null) {
				Text[] fragments = content.fragments();
				String newName = "";
				for (Text text : fragments) {
					newName += text;
				}
			}
		}
		return null;
	}

	// 分面
	private List<Map<String, Object>> facet(SearchResponse searchResponse) {
		List<Map<String, Object>> facetList = new ArrayList<>();
		for (InstanceAggField aggField : InstanceAggField.values()) {
			// 解析分面
			Terms terms = searchResponse.getAggregations().get(aggField.getType());
			List<Map<String, Object>> aggs = new ArrayList<Map<String, Object>>();
			Map<String, Object> resMap = new HashMap<String, Object>();
			resMap.put(aggField.getType(), aggs);
			for (Bucket bucket : terms.getBuckets()) {
				if(StringUtils.isBlank(bucket.getKeyAsString())) {
					continue;
				}
				Map<String, Object> facet = new HashMap<String, Object>();
				facet.put("name", bucket.getKey());
				facet.put("count", bucket.getDocCount());
				aggs.add(facet);
			}
			// 年份排序
			if ("year".equals(aggField.getType())) {
				Collections.sort(aggs, new Comparator<Map<String, Object>>() {
					@Override
					public int compare(Map<String, Object> map1, Map<String, Object> map2) {
						return map2.get("name").toString().compareTo(map1.get("name").toString());
					}
				});
			}
			// 其他统计

			Map<String, Object> otherMap = new HashMap<String, Object>();
			Missing miss = searchResponse.getAggregations().get(aggField.getType() + "Other");
			if (miss.getDocCount() > 0) {
				otherMap.put("name", "其他");// 年份异常 不能转int的数据
				otherMap.put("count", miss.getDocCount());
				aggs.add(otherMap);
			}

			facetList.add(resMap);
		}
		
		
		return facetList;

	}

}
